﻿/////////////////////////////////////////////////////////////////////////////////
//
// PlainText
// - Gets rid of unwanted formatting
// (C) Copyright Johan Åhlén 2009
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
// See the GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see http://www.gnu.org/licenses/.
//
// More info on PlainText website: http://plaintext.codeplex.com
//
/////////////////////////////////////////////////////////////////////////////////


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.Security.Permissions;
using System.Diagnostics;

namespace AdvantIQ.PlainText
{
    /// <summary>
    /// Main window. Also responsible for displaying the systray icon and systray context menu.
    /// </summary>
    public partial class MainWnd : Form
    {
        /// <summary>
        /// Key used when enabling autostart. Must be distinguishable from other applications.
        /// </summary>
        public const string AppKey = "AdvantIQ.PlainText";
        
        /// <summary>
        /// Range of user selectable hotkeys.
        /// </summary>
        public const string AllowedHotKeys = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        
        /// <summary>
        /// Message sent when Windows shuts down. Will be recognized by PlainText so it also shuts down.
        /// </summary>
        public const int WM_QUERYENDSESSION = 0x11;

        /// <summary>
        /// Indicator whether hotkey has been registered or not.
        /// </summary>
        private bool hotkeyIsRegistered = false;

        /// <summary>
        /// Indicator whether PlainText is shutting down.
        /// </summary>
        private bool endSessionPending = false;

        /// <summary>
        /// Main constructor
        /// </summary>
        public MainWnd()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Registers a hotkey, optionally unregistering previous hotkey
        /// </summary>
        /// <param name="modifiers">Modifiers</param>
        /// <param name="keyCode">Key (ascii value)</param>
        public void RegisterHotkey(int modifiers, int keyCode)
        {
            if (hotkeyIsRegistered)
                UnregisterHotkey();

            NativeMethods.RegisterHotKey(this.Handle, this.GetType().GetHashCode(), modifiers, keyCode);
            hotkeyIsRegistered = true;
        }

        /// <summary>
        /// Registers a hotkey using the appsettings.
        /// </summary>
        public void RegisterHotkey()
        {
            RegisterHotkey(Properties.Settings.Default.HotkeyModifiers, Properties.Settings.Default.HotkeyChar);
        }

        /// <summary>
        /// Unregisters a hotkey.
        /// </summary>
        public void UnregisterHotkey()
        {
            if (hotkeyIsRegistered)
            {
                NativeMethods.UnregisterHotKey(this.Handle, this.GetType().GetHashCode());
                hotkeyIsRegistered = false;
            }
        }

        /// <summary>
        /// Event handler for handling hotkeys
        /// </summary>
        private void OnHotKey()
        {
            try
            {
                // Gets clipboard contents in Unicode text format
                string str = Clipboard.GetText();

                // Exit if contents could not be represented as text
                if (str == null)
                    return;

                foreach (var filter in Filter.GetEnabledFilters())
                {
                    str = filter.Apply(str);
                }

                // Write back to clipboard
                Clipboard.SetDataObject(str, true, Properties.Settings.Default.RetryTimes, Properties.Settings.Default.RetryDelay);
            }
            catch
            {
                // Catch any errors and do not bother the user
            }

            // Simulate that the user has pressed Ctrl-V to paste to current application
            SendKeys.Send("^v");
        }

        /// <summary>
        /// Message pump. Detects WM_HOTKEY and WM_QUERYENDSESSION.
        /// </summary>
        /// <param name="m"></param>
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == NativeMethods.WM_HOTKEY)
            {
                OnHotKey();
            }
            else if (m.Msg == WM_QUERYENDSESSION)
            {
                endSessionPending = true;
            }
            base.WndProc(ref m);
        }

        /// <summary>
        /// OnLoad event handler.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PlainText_Load(object sender, EventArgs e)
        {
            InitSettings();

            RegisterHotkey();

            // Start the timer to cause a delayed minimize
            if (System.Environment.CommandLine.Contains("/silent"))
            {
                MinimizeInTray();
            }
            else
            {
            }
        }

        /// <summary>
        /// Init default settings in case configuration file is missing.
        /// </summary>
        private void InitSettings()
        {
            if (Properties.Settings.Default.HotkeyChar == 0)
            {
                Properties.Settings.Default.HotkeyChar = 86; // V
                Properties.Settings.Default.HotkeyModifiers = 8; // Windows key
                Properties.Settings.Default.Filters = new System.Collections.Specialized.StringCollection();
                Properties.Settings.Default.Filters.Add("Remove HTML|Removes all HTML tags.|Singleline|<[^>]*>|");
                Properties.Settings.Default.EnabledFilters = ""; // No enabled filters by default
                Properties.Settings.Default.RetryTimes = 3; // in ms
                Properties.Settings.Default.RetryDelay = 100; // in ms
                Properties.Settings.Default.Save();
            }
        }

        /// <summary>
        /// OnClosed event handler.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PlainText_FormClosed(object sender, FormClosedEventArgs e)
        {
            UnregisterHotkey();
        }

        /// <summary>
        /// Double click event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void notifyIcon_DoubleClick(object sender, EventArgs e)
        {
            ShowFromTray();
        }

        /// <summary>
        /// Menu-Options event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void optionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            OptionsDlg dlg = new OptionsDlg();
            if (dlg.ShowDialog() == DialogResult.OK)
            {
                RegisterHotkey();
            }
        }

        /// <summary>
        /// Menu-About event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ShowFromTray();
        }

        /// <summary>
        /// Menu-exit event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // Set endSessionPending to true to prevent OnClosing event handler from interception
            endSessionPending = true;
            this.Close();
        }

        /// <summary>
        /// Button-OK event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OKBtn_Click(object sender, EventArgs e)
        {
            MinimizeInTray();
        }

        /// <summary>
        /// Menu-License event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void licenseInfoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            LicenseDlg dlg = new LicenseDlg();
            dlg.ShowDialog();
        }

        /// <summary>
        /// OnClosing event handler. Optionally intercepts closing and minimizes to tray instead.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainWnd_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (endSessionPending)
            {
                e.Cancel = false;
            }
            else
            {
                e.Cancel = true;
                MinimizeInTray();
            }
        }

        /// <summary>
        /// Minimizes to system tray
        /// </summary>
        private void MinimizeInTray()
        {
            this.WindowState = FormWindowState.Minimized;
            this.ShowInTaskbar = false;
            this.Visible = false;

            // For some reason, the hotkey needs to be registered again after ShowInTaskBar has been changed
            RegisterHotkey();
        }

        /// <summary>
        /// Restores from system tray
        /// </summary>
        private void ShowFromTray()
        {
            this.WindowState = FormWindowState.Normal;
            this.ShowInTaskbar = true;
            this.Visible = true;

            // For some reason, the hotkey needs to be registered again after ShowInTaskBar has been changed
            RegisterHotkey();
        }

        private void OptionsBtn_Click(object sender, EventArgs e)
        {
            optionsToolStripMenuItem_Click(sender, e);
        }

        private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            Process.Start(CodePlexLinkLbl.Text);
        }
    }
}
